home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / osr5 / sco / scripts / unarch < prev    next >
Encoding:
Korn shell script  |  1997-08-26  |  10.4 KB  |  360 lines

  1. #!/bin/ksh
  2. # @(#) unarch.ksh 2.8 97/07/27
  3. # 92/10/08 john h. dubois iii (john@armory.com)
  4. # 92/10/31 make it actually work if archive isn't in current dir!
  5. # 93/11/10 Added pack and gzip archive support
  6. # 94/10/22 Added -h option.
  7. # 95/01/29 Work with cpio too (generalized from untar)
  8. # 95/08/19 Understand packed extensions (.tgz, etc.).  More verbose messages.
  9. #          If everything in the archive is under one dir, make that be the
  10. #          main dir.  Added f option.
  11. # 95/12/20 v5 mvdir does not recognize --; work around it.
  12. # 96/03/29 Added arc.
  13. # 96/04/19 Catch files with unknown archive type.  Added zip.
  14. # 96/04/27 Added t option.
  15. # 96/04/30 Added c1 options.
  16. # 96/09/13 Added e option.
  17. # 96/11/01 Added hzip and bzip support.
  18. # 96/11/27 Added d option.
  19. # 96/12/27 Added arj support.
  20. # 97/01/17 Added shar support.
  21. # 97/03/11 Added ar support.
  22. # 97/07/27 Do not give -c to uncompressors
  23.  
  24. name=${0##*/}
  25. Usage=\
  26. "Usage: $name [-cfht1] [-e<ext>] [-d<directory>]
  27.        archive[.[tar|a|cpio|shar][.[Z|[ghb]z]]|t[ghb]z|tz|arc|zip|arj] ..."
  28. Force=false
  29. Tell=false
  30. NoArchDir=false
  31. One=false
  32. pExt=
  33. fixedDir=
  34. typeset -i debug=0
  35. function debug {
  36.     if [ debug -ge $1 ]; then
  37.     shift
  38.     print -ru2 -- "$*"
  39.     fi
  40. }
  41.  
  42. while getopts :cfht1x:e:d: opt; do
  43.     case $opt in
  44.     h)
  45.     echo \
  46. "$name: extract archives into directories, uncompressing if required.
  47. $Usage
  48. If an archive name given does not end in a recognized extension, it is searched
  49. for with each possible extensions in turn.  The real filename must end with one
  50. of them.  A directory with the name of the archive is created in the current
  51. directory (not necessarily the directory that the archive is in), and the
  52. contents of the archive are extracted into it.  Absolute pathnames in tar and
  53. cpio archives are suppressed.
  54. Options:
  55. -c: Extract files relative to current directory (don't create archive dirs).
  56. -d<directory>: Extract files into <directory> instead of a directory derived
  57.     from the archive name.  Only one archive name should be given.
  58. -f: Extract an archive even if the directory it would be extracted into already
  59.     exists.
  60. -e<ext>: For the purpose of determining archive type, treat all filenames as
  61.     though <ext> was tacked onto them.  For the purpose of reading the files,
  62.     the file names are left alone, so they must be the real names of the input
  63.     files.  This allows processing of files that do not include their
  64.     compression or compression & archive type extensions.
  65.     Examples: \"$name -etar.Z foo\" and \"$name -eZ foo.tar\" will both treat
  66.     the file foo as though it was foo.tar.Z.  
  67. -h: Print this help.
  68. -t: Tell what is in an archive, without writing any files.
  69.     This does not work for sharfiles.
  70. -1: Treat only the first non-option argument as an archive name.  Any arguments
  71.     given after it are the names of files to extract; if any are given, only
  72.     those files are extracted.  This does not work for sharfiles."
  73.     exit 0
  74.     ;;
  75.     c)
  76.     NoArchDir=true
  77.     ;;
  78.     d)
  79.     fixedDir=$OPTARG
  80.     ;;
  81.     e)
  82.     pExt=.$OPTARG
  83.     ;;
  84.     1)
  85.     One=true
  86.     ;;
  87.     f)
  88.     Force=true
  89.     ;;
  90.     t)
  91.     Tell=true
  92.     NoArchDir=true
  93.     ;;
  94.     x)
  95.     if [[ "$OPTARG" != +([0-9]) ]]; then
  96.         print -ru2 -- "$name: Option -x must be given an integer argument."
  97.         exit 1
  98.     fi
  99.     debug=$OPTARG || exit 1
  100.     ;;
  101.     +?)
  102.     print -u2 "$name: options should not be preceded by a '+'."
  103.     exit 1
  104.     ;;
  105.     :) 
  106.     print -r -u2 -- \
  107.     "$name: Option '$OPTARG' requires a value.  Use -h for help."
  108.     exit 1
  109.     ;;
  110.     ?)
  111.     print -u2 "$name: $OPTARG: bad option.  Use -h for help."
  112.     exit 1
  113.     ;;
  114.     esac
  115. done
  116.  
  117. # remove args that were options
  118. let OPTIND=OPTIND-1
  119. shift $OPTIND
  120.  
  121. if [ $# -lt 1 ]; then
  122.     print -u2 "$Usage\nUse -h for help."
  123.     exit 1
  124. fi
  125.  
  126. OWD=$PWD
  127.  
  128. # @(#) glob.ksh 1.0 95/07/29
  129. # 95/07/29 john h. dubois iii
  130. # Usage: Glob <Pattern> ...
  131. # Glob() sets the global Glob_ret[] to contain the results of globbing on
  132. # the given filename patterns.  The difference between this and using the
  133. # patterns directly is that Glob_ret[] will not contain any entries for
  134. # patterns that did not match any filenames.
  135. # Note that only 1024 filenames can be stored in Glob_ret[].  If the
  136. # globbing produces more than 1024 matches, Glob() will return 2.
  137. # Unfortunately, it isn't possible to set the global positional parameters
  138. # (which can have more than 1024 elements) from within a function.
  139. # Example: Glob ".[!.]*" "*"
  140. # This will set Glob_ret[] to all filenames in the current directory except
  141. # .  and ..
  142. # Return value: 1 if any of the patterns did not match; 2 if more than 1024
  143. # matched resulted; else 0.
  144. function Glob {
  145.     set +o noglob    # Turn on globbing; local to this function
  146.     # In order for a pattern contained in a shell var to be globbed, the shell
  147.     # var must not be quoted.  But, if the pattern contains any whitespace, the
  148.     # pattern will be split into words on the whitespace before globbing.
  149.     # To get around this, we set IFS to the null string so no word splitting
  150.     # will occur.  But, this causes ${array[*]} to be expanded as a single
  151.     # word, so we have to glob each element of the array individually.
  152.     typeset Patterns OIFS=$IFS IFS
  153.     typeset -i NumPats=$# NoMatch=0 PatNum=0
  154.     set -A Patterns -- "$@"
  155.     unset Glob_ret[*]
  156.     while [ PatNum -lt NumPats ]; do
  157.     IFS=
  158.     set -- ${Patterns[PatNum]}
  159.     IFS=$OIFS
  160.     if [ $# = 1 -a "$1" = "${Patterns[PatNum]}" -a ! -a "$1" ]; then
  161.         NoMatch=1
  162.     else
  163.         set -A Glob_ret -- "${Glob_ret[@]}" "$@" || return 2
  164.     fi
  165.     let PatNum+=1
  166.     done
  167.     return $NoMatch
  168. }
  169.  
  170. if $One; then
  171.     # Move everything except 1st arg to file list
  172.     Arch=$1
  173.     shift
  174.     set -A FileList -- "$@"
  175.     set -- "$Arch"
  176. else
  177.     unset FileList
  178. fi
  179.  
  180. for file in "$@"; do
  181.     debug 1 "Processing: $file"
  182.     cd -- "$OWD"
  183.  
  184.     tName="$file$pExt"
  185.     ## Determine what the real archive full & base names are
  186.     if [[ "$tName" = \
  187.     *.@(@(tar|a|cpio|shar)?(.@(z|Z|[ghb]z))|[ct]@(Z|z|[ghb]z)|ar[cj]|zip) ]]
  188.     then
  189.     # If file was given with a known extension, the archive name
  190.     # is the filename without the extension.
  191.     ArchName=\
  192. ${tName%%.@(@(tar|a|cpio|shar)?(.@(z|Z|[ghb]z))|[ct]@(Z|z|[ghb]z)|ar[cj]|zip)}
  193.     debug 1 "$tName has known extension; archive name = $ArchName"
  194.     elif [ -n "$pExt" ]; then
  195.     print -u2 "$name: Unknown archive type: $tName"
  196.     continue
  197.     else
  198.         ArchName=$file
  199.     file=
  200.     # The filename did not have a known extension; try attaching all
  201.     # known extensions and see if the archive exists.
  202.     for ext in \
  203.     {tar,a,cpio,shar}{,.Z,.z,.{g,h,b}z} {t,c}{z,Z,{g,h,b}z} arc arj zip; do
  204.         debug 3 "Searching for file as: $ArchName.$ext"
  205.         if [ -f "$ArchName.$ext" ]; then
  206.         file="$ArchName.$ext"
  207.         break
  208.         fi
  209.     done
  210.     if [ -z "$file" ]; then
  211.         print -u2 -- \
  212. "$name: Unknown archive type (not found with any known extension):
  213. $ArchName"
  214.         continue
  215.     fi
  216.     debug 1 "No known extension in $ArchName; found archive file as $file"
  217.     tName=$file
  218.     fi
  219.     if [ ! -r "$file" ]; then
  220.     print -u2 "$name: Cannot read archive file: $file"
  221.     continue
  222.     fi
  223.  
  224.     [[ "$file" != /* ]] && file="$OWD/$file"
  225.     if $Tell; then
  226.     print "Contents of archive $file:"
  227.     elif $NoArchDir; then
  228.     print "Extracting archive $file into current directory ($PWD)..."
  229.     else
  230.     if [ -n "$fixedDir" ]; then
  231.         DirName=$fixedDir
  232.     else
  233.         DirName=${ArchName##*/}
  234.     fi
  235.     # If the directory doesn't already exist in the local dir, make it.
  236.     if [ -a "$DirName" ]; then
  237.         if [ ! -d "$DirName" ]; then
  238.         print -u2 \
  239. "$name: $DirName already exists in the current directory 
  240. and is not a directory.  It must be removed in order to
  241. extract the archive \"$file\"."
  242.         continue
  243.         fi
  244.         $Force || {
  245.         print -u2 \
  246. "$name: The directory $DirName already exists.  It must be removed,
  247. or the -f option must be used to force extraction into it."
  248.         continue
  249.         }
  250.     else
  251.         mkdir "$DirName" || {
  252.         print -u2 "$name: Could not make archive directory: $DirName"
  253.         continue
  254.         }
  255.         debug 1 "Created directory $DirName"
  256.     fi
  257.     cd -- "$DirName"
  258.     print "Extracting archive $file into directory $DirName"
  259.     fi
  260.     case "$tName" in
  261.     *.?([ct])Z)
  262.     uncomp=zcat
  263.     compression="compressed "
  264.     ;;
  265.     *.?([ct])z)
  266.     uncomp=pcat
  267.     compression="packed "
  268.     ;;
  269.     *.?([ct])[ghb]z)
  270.     l=${tName##*.}
  271.     l=${l#[ct]}
  272.     l=${l%z}
  273.     # Do not give -c to uncompressor, because input is always redirected
  274.     # into it and some do not like being given -c if not given a filename
  275.     uncomp="${l}zip -d"
  276.     compression="${l}zipped "
  277.     ;;
  278.     *) uncomp=
  279.     compression=
  280.     ;;
  281.     esac
  282.     debug 1 "Uncompressor=$uncomp"
  283.     case "$tName" in
  284.     *.tar?(.@(z|Z|[ghb]z))|*.t@(Z|z|[ghb]z))
  285.     $Tell && x=t || x=x
  286.     # Redirect input to uncompress routines because file might not end
  287.     # with the extension they expect
  288.     [ -z "$uncomp" ] && tar nvAf$x "$file" "${FileList[@]}" ||
  289.     $uncomp < "$file" | tar vAf$x - "${FileList[@]}"
  290.     arch=tar
  291.     ;;
  292.     *.a?(.@(z|Z|[ghb]z))|*.t@(Z|z|[ghb]z))
  293.     $Tell && x=t || x=x
  294.     # Redirect input to uncompress routines because file might not end
  295.     # with the extension they expect
  296.     [ -z "$uncomp" ] && ar v$x "$file" "${FileList[@]}" ||
  297.     $uncomp < "$file" | ar v$x /dev/stdin "${FileList[@]}"
  298.     arch=ar
  299.     ;;
  300.     *.cpio?(.@(z|Z|[ghb]z))|*.c@(Z|z|[ghb]z))
  301.     $Tell && x=t || x=
  302.     [ -z "$uncomp" ] && cpio -${x}idmvAI "$file" "${FileList[@]}" ||
  303.     $uncomp < "$file" | cpio -${x}idmvA "${FileList[@]}"
  304.     arch=cpio
  305.     ;;
  306.     *.shar?(.@(z|Z|[ghb]z))|*.c@(Z|z|[ghb]z))
  307.     if $One; then
  308.         print -u2 -- "$name: Cannot use -1 with a sharfile.  Skipping."
  309.         continue
  310.     fi
  311.     if $Tell; then
  312.         print -u2 -- "$name: Cannot use -t with a sharfile.  Skipping."
  313.         continue
  314.     fi
  315.     [ -z "$uncomp" ] && unshar -f "$file" "${FileList[@]}" ||
  316.     $uncomp < "$file" | unshar -f "${FileList[@]}"
  317.     arch=shell
  318.     ;;
  319.     *.arj)
  320.     $Tell && x=l || x=e
  321.     unarj $x "$file" "${FileList[@]}"
  322.     arch=arj
  323.     ;;
  324.     *.arc)
  325.     $Tell && x=v || x=e
  326.     arc $x "$file" "${FileList[@]}"
  327.     arch=arc
  328.     ;;
  329.     *.zip)
  330.     $Tell && x=v || x=e
  331.     unzip -$x "$file" "${FileList[@]}"
  332.     arch=zip
  333.     ;;
  334.     *)
  335.     # Shouldn't be able to get here!
  336.     print -u2 "Fatal error: unknown extension in $tName"
  337.     exit 1
  338.     ;;
  339.     esac
  340.     $Tell && continue
  341.     print \
  342. "Done extracting $compression$arch archive $file
  343. into directory: $DirName"
  344.     $NoArchDir && continue
  345.     Glob ".[!.]*" "*"
  346.     if [ ${#Glob_ret[*]} = 1 -a -d "${Glob_ret[0]}" ]; then
  347.     root=${Glob_ret[0]}
  348.     print \
  349. "Archive root contains one directory, \"$root\".
  350. Moving $DirName/$root to: $DirName"
  351.     # mvdir does not recognize -- to end option list, so use ./
  352.     cd .. &&
  353.     mvdir "./$DirName" "$DirName.$$" &&
  354.     mvdir "./$DirName.$$/$root" "$DirName" &&
  355.     rmdir -- "$DirName.$$" &&
  356.     print "Directory move completed successfully." ||
  357.     print "Directory move failed."
  358.     fi
  359. done
  360.